﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
using UnityEngine.XR;

namespace lights
{
    /// <summary>
    /// fp32 有 固定 1000 小数底 的版本，该版本用来计数，精度太差不宜计算
    /// </summary>
    public struct fp32_kd
    {
        public int value;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public fp32_kd(int v)
        {
            this.value = v;
        }

        #region 常量

        public const int Scalar = 1000;

        public const int NUM_BITS = 32;

        public static readonly fp32_kd half = new fp32_kd(Scalar / 2);
        public static readonly fp32_kd zero = new fp32_kd(0);
        public static readonly fp32_kd one = new fp32_kd(Scalar);
        #endregion

        #region 类型转换
        //作为浮点数显示
        public override string ToString()
        {
            var h = value / Scalar;
            var l = value % Scalar;
            return h + "." + l.ToString("d03");
        }
        //精确表达
        public string ToStringFix()
        {
            var h = value / Scalar;
            var l = value % Scalar;
            return h + "+" + l + "/" + Scalar;
        }





        public const int MinValue = -2147483648;
        public static fp32_kd FromFloat(float v)
        {
            return new fp32_kd((int)(v * Scalar));
        }
        public static fp32_kd FromInt(int v)
        {
            return new fp32_kd(v * Scalar);
        }
        public static fp32_kd FromFp32(fp32 v)
        {
            var h = v.value / fp32.Scalar;
            var l = (v.value % fp32.Scalar) * Scalar / fp32.Scalar;
            return new fp32_kd(h * Scalar + l);
        }

        public float ToFloat()
        {
            var h = (float)(value / Scalar);
            var l = (float)(value % Scalar);
            return (float)h + (l / (float)Scalar);
        }
        public int ToInt()
        {
            return value / Scalar;
        }
        public static fp32 ToFp32(fp32_kd v)
        {
            var h = v.value / Scalar;
            var l = (v.value % Scalar) * fp32.Scalar / Scalar;
            return new fp32(h * fp32.Scalar + l);
        }

        #endregion
        #region math计算
        public static fp32_kd Floor(fp32_kd v)
        {
            return new fp32_kd((v.value / 1000) * 1000);
        }
        public static fp32_kd Abs(fp32_kd v)
        {
            return (v.value >= 0) ? v : new fp32_kd(-v.value);
        }
        #endregion

        #region 四则运算
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static fp32_kd operator +(fp32_kd lhs, fp32_kd rhs) { return new fp32_kd(lhs.value + rhs.value); }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static fp32_kd operator -(fp32_kd lhs, fp32_kd rhs) { return new fp32_kd(lhs.value - rhs.value); }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static fp32_kd operator *(fp32_kd lhs, fp32_kd rhs)
        {
            return new fp32_kd((int)(((long)lhs.value * (long)rhs.value) / Scalar));
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static fp32_kd operator /(fp32_kd lhs, fp32_kd rhs)
        {

            if (rhs.value == MinValue || rhs.value == 0)
            {
                throw new System.Exception("Fixed32.Div zero error.");

            }

            return new fp32_kd((int)(((long)lhs.value * Scalar) / rhs.value));
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static fp32_kd operator %(fp32_kd lhs, fp32_kd rhs)
        {

            if (rhs.value == 0)
            {
                throw new System.Exception("Fixed32.Mod zero error.");

            }

            return new fp32_kd(lhs.value % rhs.value);
        }

        public static fp32_kd operator -(fp32_kd a)
        {
            return new fp32_kd(-a.value);
        }

        #endregion
        ///Compare 方法
        #region Compare方法
        public override bool Equals(object other)
        {
            if (other is fp32_kd v)
            {
                return this.value == v.value;
            }
            else
            {
                return false;
            }
        }
        public override int GetHashCode()
        {
            return value;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator <(fp32_kd lhs, fp32_kd rhs) { return lhs.value < rhs.value; }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator >(fp32_kd lhs, fp32_kd rhs) { return lhs.value > rhs.value; }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator <=(fp32_kd lhs, fp32_kd rhs) { return lhs.value <= rhs.value; }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator >=(fp32_kd lhs, fp32_kd rhs) { return lhs.value >= rhs.value; }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator ==(fp32_kd lhs, fp32_kd rhs) { return lhs.value == rhs.value; }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator !=(fp32_kd lhs, fp32_kd rhs) { return lhs.value != rhs.value; }


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static fp32_kd Min(fp32_kd x, fp32_kd y)
        {
            return x.value < y.value ? x : y;
        }


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static fp32_kd Max(fp32_kd x, fp32_kd y)
        {
            return x.value > y.value ? x : y;
        }
        #endregion


    }
}
